package com.xuyuan.remote;

import com.alibaba.fastjson.JSONObject;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.entity.mime.FileBody;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.client5.http.entity.mime.StringBody;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.*;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.message.BasicHeader;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.hc.core5.net.URIBuilder;
import org.apache.hc.core5.util.Timeout;
import org.springframework.http.HttpHeaders;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static java.nio.charset.StandardCharsets.UTF_8;

public class HttpClientExample {
    private static final String URL = "http://example.com";

    /**
     * GET请求
     */
    public static void testGET() throws IOException, URISyntaxException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        URIBuilder builder = new URIBuilder("http://example.com");

        // 添加请求参数 -1
        builder.setParameter("var1", "param1").setParameter("var2", "param2");
        // 添加请求参数 -2
        builder.setParameters(new BasicNameValuePair("var1", "param1"), new BasicNameValuePair("var2", "param2"));
        // 添加请求参数 -3 addParameter 会保留重名的参数，setParameter会替换
        builder.addParameter("var1", "param1").addParameter("var2", "param2");

        // 添加路径参数 -1 setPathSegments 会覆盖之前的路径
        builder.setPathSegments("pathVar1", "pathVar2");
        // 添加路径参数 -2  setPath 会覆盖之前设置的路径
        builder.setPath("/pathVar1/pathVar2");
        // 添加路径参数 -3  appendPath 路径后面拼接添加
        builder.appendPath("pathVar1").appendPath("pathVar2");
        builder.appendPathSegments("pathVar1", "pathVar2");

        URI url = builder.build();
        HttpGet httpget = new HttpGet(url);

        CloseableHttpResponse response = httpClient.execute(httpget);
        if (response.getCode() == 200) {
            System.out.println("调用成功。开始处理响应");
        }
        response.close();
        httpClient.close();
    }

    /**
     * POST请求
     */
    public static void testPOST() throws IOException {
        // 创建httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建请求对象
        HttpPost httpPost = new HttpPost(URL);
        // post请求设置请求参数（JSON格式）
        StringEntity entity = new StringEntity("123", ContentType.APPLICATION_JSON, "utf-8", false);
        // 设置请求参数
        httpPost.setEntity(entity);
        // 发送请求
        CloseableHttpResponse response = httpClient.execute(httpPost);
        // 处理响应
        if (response.getCode() == 200) {
            System.out.println("调用成功。开始处理响应");
        }
        // 关闭资源
        response.close();
        httpClient.close();
    }

    /**
     * HttpEntity - JSON/复杂对象->JSON
     *
     * @throws IOException
     * @throws ParseException
     */
    public static void jsonBody() throws IOException, ParseException {
        // 创建httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建请求对象
        HttpPost httpPost = new HttpPost(URL);

        // post请求设置请求参数（JSON格式）
        Map<String, Object> map = new HashMap<>();
        map.put("username", "admin");
        map.put("password", "123456");
        Map<String, Object> extendMap = new HashMap<>();
        map.put("exts", extendMap);
        extendMap.put("xxx", "111");
        JSONObject jsonObject = new JSONObject(map);
        StringEntity entity = new StringEntity(jsonObject.toString(), ContentType.APPLICATION_JSON, "utf-8", false);
        // 设置请求参数
        httpPost.setEntity(entity);

        // 发送请求
        CloseableHttpResponse response = httpClient.execute(httpPost);
        // 处理响应
        if (response.getCode() == 200) {
        }
        // 关闭资源
        response.close();
        httpClient.close();
    }

    /**
     * HttpEntity - 表单
     */
    public static void formBody() throws Exception {
        // 创建默认的httpClient实例.
        CloseableHttpClient httpclient = HttpClients.createDefault();
        // 创建httppost
        HttpPost httppost = new HttpPost(URL);
        // 创建参数队列
        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
        formparams.add(new BasicNameValuePair("username", "admin"));
        formparams.add(new BasicNameValuePair("password", "123456"));
        UrlEncodedFormEntity uefEntity;
        uefEntity = new UrlEncodedFormEntity(formparams, UTF_8);
        httppost.setEntity(uefEntity);
        CloseableHttpResponse response = httpclient.execute(httppost);
        // 处理响应
        if (response.getCode() == 200) {
            System.out.println("调用成功。开始处理响应");
        }
        httpclient.close();
        response.close();
    }

    /**
     * 定制化HttpClient
     */
    public void customConfig() throws IOException {
        RequestConfig defaultConfig = RequestConfig.DEFAULT;
        // 定制化请求
        RequestConfig customConfig = RequestConfig.custom().setAuthenticationEnabled(true) // 允许在请求中使用身份验证信息
                .setTargetPreferredAuthSchemes(Arrays.asList("Basic")) // 定义了在请求发送到目标服务器时优先选择的身份验证机制
                .setProxyPreferredAuthSchemes(Arrays.asList("Basic", "Digest")) // 定义了在使用代理服务器时优先选择的身份验证机制
                .setConnectionRequestTimeout(Timeout.ofMilliseconds(10000)) // 从连接池获取连接的超时时间
                .setResponseTimeout(Timeout.ofMilliseconds(10000)) // 等待服务器响应的超时时间。
                .setConnectionKeepAlive(Timeout.ofMilliseconds(10000))  // 是否启用长连接策略
                .setDefaultKeepAlive(10000L, TimeUnit.MILLISECONDS) // 连接的存活时间
                .setContentCompressionEnabled(true) // 是否启用内容压缩
                .setHardCancellationEnabled(true) // 是否允许强制取消该请求，即中断正在进行的HTTP操作
                .setCookieSpec("") // 设置用于处理Cookie的规范
                .setRedirectsEnabled(true) // 是否允许重定向
                .setCircularRedirectsAllowed(false) // 是否允许循环重定向
                .setMaxRedirects(5) // 最大重定向次数
                .setExpectContinueEnabled(true)
                // 启用Expect/Continue握手。HTTP/1.1特性，允许客户端在发送实际请求体之前，先发送一个带有Expect: 100-continue的请求头
                // 以检查服务器是否愿意接收请求体,有助于避免在服务器拒绝请求时浪费带宽发送大量数据。
                .build();
        // 定制化客户端
        // CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(customConfig) // 设置默认的请求配置
        //         .setRequestExecutor() //  设置请求执行器,用于定制请求的执行方式
        //         .setConnectionManager() // 设置一个自定义的连接管理器，管理HTTP连接池和连接的分配
        //         .setConnectionManagerShared() // 指定连接管理器是否为共享的
        //         .setConnectionReuseStrategy() // 设置连接重用策略
        //         .setKeepAliveStrategy()  // 设置长连接策略
        //         .setTargetAuthenticationStrategy()  //  设置目标主机认证策略
        //         .setProxyAuthenticationStrategy() // 设置代理认证策略
        //         .setUserTokenHandler() // 设置用户令牌处理器
        //         .setSchemePortResolver() // 设置方案端口解析器
        //         .setUserAgent() // 设置用户代理
        //         .setDefaultHeaders() // 设置默认的请求头
        //         .addResponseInterceptorFirst()  // 响应拦截器，可以在处理响应前或后，对HTTP响应进行拦截和处理
        //         .addResponseInterceptorLast().addRequestInterceptorFirst() // 添加请求拦截器，对HTTP请求进行拦截和处理
        //         .addRequestInterceptorLast().addExecInterceptorBefore() // 添加执行拦截器，对HTTP请求和响应进行拦截和处理
        //         .addExecInterceptorAfter().replaceExecInterceptor() // 替换已存在的执行拦截器
        //         .addExecInterceptorFirst()  // 可以在执行拦截器链的开头或结尾添加新的拦截器
        //         .addExecInterceptorLast().setRetryStrategy() // 设置在遇到特定条件时如何进行HTTP请求的重试
        //         .setProxy() // 设置用于HTTP请求的代理服务器
        //         .setRoutePlanner() // 设置如何计算请求的路由
        //         .setRedirectStrategy() // 设置如何处理HTTP重定向
        //         .setConnectionBackoffStrategy() // 设置在发生连接问题时的退避策略
        //         .setDefaultCookieStore() // 设置用于管理HTTP请求中的Cookie
        //         .setDefaultCredentialsProvider() // 设置用于处理HTTP身份验证的默认凭据提供者
        //         .setDefaultAuthSchemeRegistry() // 设置用于HTTP认证方案的注册表
        //         .setDefaultCookieSpecRegistry() // 设置用于管理Cookie规范的注册表
        //         .setContentDecoderRegistry() // 设置用于管理HTTP内容解码器的注册表
        //         .evictIdleConnections() // 定期清理连接池中的空闲连接
        //         .setProxySelector() // 设置如何选择要使用的代理
        //         .build();
    }

    /**
     * 添加HTTP的Header
     */
    public void addHeader() throws IOException {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet(URL);

        // 添加自定义报文头
        httpget.addHeader("custom-head1", "xxxxxxxxx");
        httpget.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        httpget.setHeader("Accept-Encoding", "gzip, deflate");
        httpget.setHeader("Connection", "keep-alive");

        // 添加标准报文头
        httpget.addHeader(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
        httpget.setHeader(HttpHeaders.HOST, URL);

        // 使用Header添加报文属性，不常用
        Header header = new BasicHeader("Connection", "keep-alive");
        httpget.addHeader(header);

        CloseableHttpResponse response = httpclient.execute(httpget);
        if (response.getCode() == 200) {
            System.out.println("调用成功。开始处理响应");
        }
        response.close();
        httpclient.close();
    }

    /**
     * HttpEntity - 文件
     */
    public void fileBody() throws IOException {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httppost = new HttpPost(URL);
        FileBody file = new FileBody(new File("C:\\image\\1.jpg"));
        StringBody comment = new StringBody("A binary file of some kind", ContentType.TEXT_PLAIN);
        HttpEntity reqEntity = MultipartEntityBuilder.create().addPart("bin", file).addPart("comment", comment).build();
        httppost.setEntity(reqEntity);
        CloseableHttpResponse response = httpclient.execute(httppost);
        if (response.getCode() == 200) {
            System.out.println("调用成功。开始处理响应");
        }
        HttpEntity rspEntity = response.getEntity();
        if (rspEntity != null) {
            System.out.println("Response content length: " + rspEntity.getContentLength());
        }
        EntityUtils.consume(rspEntity);

        httpclient.close();
        response.close();
    }
}